gl renderer: Linear gradient state tracking
authorTimm Bäder <mail@baedert.org>
Fri, 24 Jul 2020 18:45:22 +0000 (20:45 +0200)
committerTimm Bäder <mail@baedert.org>
Tue, 28 Jul 2020 03:34:12 +0000 (05:34 +0200)
gsk/gl/gskglrenderer.c
gsk/gl/gskglrenderops.c
gsk/gl/gskglrenderopsprivate.h
gsk/gl/opbuffer.h

index 7346912eefcc95c65328289d7faf260f1225ba0b..e2e5d853208c91c36e8c60ef7b9603b9a614c3fa 100644 (file)
@@ -1129,16 +1129,15 @@ render_linear_gradient_node (GskGLRenderer   *self,
   const GskColorStop *stops = gsk_linear_gradient_node_peek_color_stops (node, NULL);
   const graphene_point_t *start = gsk_linear_gradient_node_peek_start (node);
   const graphene_point_t *end = gsk_linear_gradient_node_peek_end (node);
-  OpLinearGradient *op;
 
   ops_set_program (builder, &self->programs->linear_gradient_program);
-  op = ops_begin (builder, OP_CHANGE_LINEAR_GRADIENT);
-  op->color_stops = stops;
-  op->n_color_stops = n_color_stops;
-  op->start_point.x = start->x + builder->dx;
-  op->start_point.y = start->y + builder->dy;
-  op->end_point.x = end->x + builder->dx;
-  op->end_point.y = end->y + builder->dy;
+  ops_set_linear_gradient (builder,
+                           n_color_stops,
+                           stops,
+                           builder->dx + start->x,
+                           builder->dy + start->y,
+                           builder->dx + end->x,
+                           builder->dy + end->y);
 
   load_vertex_data (ops_draw (builder, NULL), node, builder);
 }
@@ -2687,12 +2686,16 @@ apply_linear_gradient_op (const Program          *program,
                           const OpLinearGradient *op)
 {
   OP_PRINT (" -> Linear gradient");
-  glUniform1i (program->linear_gradient.num_color_stops_location, op->n_color_stops);
-  glUniform1fv (program->linear_gradient.color_stops_location,
-                op->n_color_stops * 5,
-                (float *)op->color_stops);
-  glUniform2f (program->linear_gradient.start_point_location, op->start_point.x, op->start_point.y);
-  glUniform2f (program->linear_gradient.end_point_location, op->end_point.x, op->end_point.y);
+  if (op->n_color_stops.send)
+    glUniform1i (program->linear_gradient.num_color_stops_location, op->n_color_stops.value);
+
+  if (op->color_stops.send)
+    glUniform1fv (program->linear_gradient.color_stops_location,
+                  op->n_color_stops.value * 5,
+                  (float *)op->color_stops.value);
+
+  glUniform2f (program->linear_gradient.start_point_location, op->start_point[0], op->start_point[1]);
+  glUniform2f (program->linear_gradient.end_point_location, op->end_point[0], op->end_point[1]);
 }
 
 static inline void
index 0ce0e2c2c02e32073cc26a59167d64f08a2c3ed8..11269eec88c2cdd25f8b796e1ae8b03d71e173b8 100644 (file)
@@ -889,3 +889,66 @@ ops_set_unblurred_outset_shadow (RenderOpBuilder      *self,
   else
     op->offset.send = FALSE;
 }
+
+void
+ops_set_linear_gradient (RenderOpBuilder     *self,
+                         guint                n_color_stops,
+                         const GskColorStop  *color_stops,
+                         float                start_x,
+                         float                start_y,
+                         float                end_x,
+                         float                end_y)
+{
+  ProgramState *current_program_state = get_current_program_state (self);
+  OpLinearGradient *op;
+  const guint real_n_color_stops = MIN (MAX_GRADIENT_STOPS, n_color_stops);
+
+  g_assert (current_program_state);
+
+  op = ops_begin (self, OP_CHANGE_LINEAR_GRADIENT);
+
+  /* We always save the n_color_stops value in the op so the renderer can use it in
+   * cases where we send the color stops, but not n_color_stops */
+  op->n_color_stops.value = real_n_color_stops;
+  if (current_program_state->linear_gradient.n_color_stops != real_n_color_stops)
+    {
+      op->n_color_stops.send = TRUE;
+      current_program_state->linear_gradient.n_color_stops = real_n_color_stops;
+    }
+  else
+    op->n_color_stops.send = FALSE;
+
+  op->color_stops.send = FALSE;
+  if (!op->n_color_stops.send)
+    {
+      g_assert (current_program_state->linear_gradient.n_color_stops == real_n_color_stops);
+
+      for (guint i = 0; i < real_n_color_stops; i ++)
+        {
+          const GskColorStop *s1 = &color_stops[i];
+          const GskColorStop *s2 = &current_program_state->linear_gradient.color_stops[i];
+
+          if (s1->offset != s2->offset ||
+              !gdk_rgba_equal (&s1->color, &s2->color))
+            {
+              op->color_stops.send = TRUE;
+              break;
+            }
+        }
+    }
+  else
+    op->color_stops.send = TRUE;
+
+  if (op->color_stops.send)
+    {
+      op->color_stops.value = color_stops;
+      memcpy (&current_program_state->linear_gradient.color_stops,
+              color_stops,
+              sizeof (GskColorStop) * real_n_color_stops);
+    }
+
+  op->start_point[0] = start_x;
+  op->start_point[1] = start_y;
+  op->end_point[0] = end_x;
+  op->end_point[1] = end_y;
+}
index de8b30ddd9964952785bc43b14072eafa24c2748..ebb39e355ae579f84cb765e37f15d9b35ed68319 100644 (file)
@@ -14,6 +14,7 @@
 
 #define GL_N_VERTICES 6
 #define GL_N_PROGRAMS 13
+#define MAX_GRADIENT_STOPS 8
 
 typedef struct
 {
@@ -136,6 +137,12 @@ typedef struct
       float spread;
       GdkRGBA color;
     } unblurred_outset_shadow;
+    struct {
+      int n_color_stops;
+      GskColorStop color_stops[MAX_GRADIENT_STOPS];
+      float start_point[2];
+      float end_point[2];
+    } linear_gradient;
   };
 } ProgramState;
 
@@ -264,6 +271,14 @@ void              ops_set_unblurred_outset_shadow   (RenderOpBuilder         *se
                                                      float                    dx,
                                                      float                    dy);
 
+void              ops_set_linear_gradient (RenderOpBuilder     *self,
+                                           guint                n_color_stops,
+                                           const GskColorStop  *color_stops,
+                                           float                start_x,
+                                           float                start_y,
+                                           float                end_x,
+                                           float                end_y);
+
 GskQuadVertex *   ops_draw               (RenderOpBuilder        *builder,
                                           const GskQuadVertex     vertex_data[GL_N_VERTICES]);
 
index 8637d79657a985e8716ddc07f5635dae9a23b061..9604f4b852de64c5ad331f828e320a4c9df4a10f 100644 (file)
@@ -42,11 +42,13 @@ typedef enum
 } OpKind;
 
 
+typedef struct { int value; guint send: 1; }    IntUniformValue;
 typedef struct { float value; guint send: 1; }    FloatUniformValue;
 typedef struct { float value[2]; guint send: 1; } Float2UniformValue;
 typedef struct { GskRoundedRect value; guint send: 1; guint send_corners: 1; } RRUniformValue;
 typedef struct { const GdkRGBA *value; guint send: 1; } RGBAUniformValue;
 typedef struct { const graphene_vec4_t *value; guint send: 1; } Vec4UniformValue;
+typedef struct { const GskColorStop *value; guint send: 1; } ColorStopUniformValue;
 
 /* OpNode are allocated within OpBuffer.pos, but we keep
  * a secondary index into the locations of that buffer
@@ -129,10 +131,10 @@ typedef struct
 
 typedef struct
 {
-  const GskColorStop *color_stops;
-  graphene_point_t start_point;
-  graphene_point_t end_point;
-  int n_color_stops;
+  ColorStopUniformValue color_stops;
+  IntUniformValue n_color_stops;
+  float start_point[2];
+  float end_point[2];
 } OpLinearGradient;
 
 typedef struct